﻿using CommunityToolkit.Mvvm.ComponentModel;
using SudukuSolver_Mvvm.Services;
using SudukuSolver_Mvvm.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace SudukuSolver_Mvvm.ViewModels
{
    public partial class SudukuViewModel : ObservableObject
    {
        public BindingList<BindingList<CellViewModel>> Suduku { get; set; }
        public MainWindowViewModel Main
        {
            get
            {
                return MainWindowViewModel.Instance;
            }
        }

        /// <summary>
        /// 创建一个空数独
        /// </summary>
        public SudukuViewModel()
        {
            // 初始化一个空的列表，所有的格子都是0
            this.Suduku = new BindingList<BindingList<CellViewModel>>();
            for (int i = 0; i < 9; i++)
            {
                var n = new BindingList<CellViewModel>();
                for (int j = 0; j < 9; j++)
                {
                    n.Add(new CellViewModel(Suduku, i, j, 0));
                }
                Suduku.Add(n);
            }
        }

        /// <summary>
        /// 通过一个二位数组初始化数独
        /// </summary>
        /// <param name="nums"></param>
        public SudukuViewModel(int[][] nums) : this()
        {
            SetNewSuduku(nums);
        }

        /// <summary>
        /// 设置一个新的数独
        /// </summary>
        /// <param name="nums"></param>
        public void SetNewSuduku(int[][] nums)
        {
            Suduku.Clear();
            for (int i = 0; i < 9; i++) // 大九宫
            {
                BindingList<CellViewModel> bigNine = new BindingList<CellViewModel>();
                for (int j = 0; j < 9; j++) // 大九宫里的每一个数字
                {
                    int colIndex = i % 3 * 3 + j % 3; // 通过九宫计算列数
                    int rowIndex = i / 3 * 3 + j / 3; // 计算行数
                    int current = nums[rowIndex][colIndex];
                    bigNine.Add(new CellViewModel(Suduku, i, j, current));
                }
                Suduku.Add(bigNine);
            }

            foreach (var item in Suduku)
            {
                foreach (var cell in item)
                {
                    cell.UpdateCases();
                }
            }
        }

        /// <summary>
        /// 清理数独，将数独恢复到原始的没填数字的样子
        /// </summary>
        public void Resume()
        {
            // 重置格子当前数字
            foreach (var nine in Suduku)
            {
                foreach (var cell in nine)
                {
                    if (cell.IsEnabled)
                    {
                        cell.Reset();
                    }
                }
            }

            // 重置格子可以填的数字的可能性
            foreach (var item in Suduku)
            {
                foreach (var cell in item)
                {
                    cell.UpdateCases();
                }
            }
        }

        /// <summary>
        /// 计算数独的入口函数
        /// </summary>
        public void Start()
        {
            Application.Current.Dispatcher.Invoke(() => Resume()); // 开始前将数独重置为初始状态
            SolveResult result = Solve(0, 0);
            Application.Current.Dispatcher.Invoke(() =>
            {
                Main.SolveState = SolveState.Stop;
            });
        }

        /// <summary>
        /// 计算数独
        /// </summary>
        /// <param name="bigNine"></param>
        /// <param name="nine"></param>
        /// <returns></returns>
        private SolveResult Solve(int bigNine, int nine)
        {
            if (Main.SolveCancel.IsCancellationRequested)
            {
                return SolveResult.Cancel;
            }
            Main.SolveReset.WaitOne();

            var cell = Suduku[bigNine][nine];
            if (!cell.IsEnabled)
            {
                // 如果当前格子不需要计算，就进行下一个；
                // 至于下一个是哪个格子，将会在Next中计算出来
                return Next(bigNine, nine);
            }
            else
            {
                // 如果当前格子需要计算，就一个一个测试
                cell.UpdateCases();
                while (cell.Next())
                {
                    if (Main.IsTestMode)
                    {
                        Thread.Sleep(200);
                    }
                    // 因为更新过这个格子的所有可能性了，所以，只要进入while循环就说明这个格子还有可以填的数

                    // 只有失败了才继续下一个，否则直接返回状态
                    var result = Next(bigNine, nine);
                    if (result == SolveResult.Failure)
                    {
                        continue;
                    }
                    else
                    {
                        return result;
                    }
                }

                if (Main.IsTestMode)
                {
                    Thread.Sleep(200);
                }
                // 这个格子所有的可能性都测试完了就是返回false
                cell.Reset();
                return SolveResult.Failure;
            }
        }

        /// <summary>
        /// 计算下一个格子
        /// </summary>
        /// <param name="bigNine">第几个大九宫</param>
        /// <param name="nine">大九宫中的第几个格子</param>
        /// <returns></returns>
        private SolveResult Next(int bigNine, int nine)
        {
            // 如果当前大九宫都计算完了，那就下一个大九宫
            // 如果所有的大九宫都计算完了，那就返回true
            if (nine < 8)
            {
                nine++;
            }
            else
            {
                if (bigNine < 8)
                {
                    bigNine++;
                    nine = 0;
                }
                else
                {
                    return SolveResult.Success;
                }
            }
            return Solve(bigNine, nine);
        }
    }
}
